package org.dreamwork.plugins.network.assistant.gui

import org.dreamwork.util.StringUtil
import org.dreamwork.util.Tools
import org.slf4j.LoggerFactory
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.DatagramPacket
import java.net.DatagramSocket

internal abstract class NetworkReader (private val name: String) : Runnable {
    var listener: NetworkReaderListener? = null
    private val log = LoggerFactory.getLogger(NetworkReader::class.java)

    protected abstract fun doWork()
    abstract fun shutdown()

    override fun run() {
        Thread.currentThread().name = name
        log.info("$name worker stated.")
        try {
            doWork()
        } catch (ex: Exception) {
            log.warn(ex.message, ex)
        }
        log.info("$name worker done!")
        if (listener != null) {
            listener!!.onClosed()
        }
    }

    interface NetworkReaderListener {
        fun onClosed()
        fun onReceived(data: ByteArray?)
    }
}

internal class TcpReader (private val stream: InputStream) : NetworkReader("TCP Reader") {
    private val al = LoggerFactory.getLogger(TcpReader::class.java)
    override fun doWork() {
        try {
            val baos = ByteArrayOutputStream()
            val buff = ByteArray(1024)
            var length: Int
            while (stream.read(buff).also { length = it } != -1) {
                baos.write(buff, 0, length)
                if (length < buff.size) {
                    val data = baos.toByteArray()
                    al.info("received data: {}", StringUtil.format(data))
                    baos.reset()
                    if (listener != null) {
                        listener!!.onReceived(data)
                    }
                }
            }
        } catch (ex: IOException) {
            ex.printStackTrace()
        }
    }

    override fun shutdown() {}
}

internal class UdpReader (private val socket: DatagramSocket, private val packet: DatagramPacket) : NetworkReader( "UDPReader") {
    private var running = true
    override fun doWork() {
        socket.use {
            while (running) {
                socket.receive(packet)
                if (packet.length > 0) {
                    val data = Tools.slice(packet.data, packet.offset, packet.length)
                    if (listener != null) {
                        listener!!.onReceived(data)
                    }
                }
            }
        }
    }

    override fun shutdown() {
        running = false
    }
}